#include "hk_lift.h"
#include <QString>
#include <QDebug>
#include <QUuid>
#include <QTcpSocket>
#include <QtGlobal>

namespace application {
namespace lift {

namespace {
struct HkPayloadView {
    int agv{-1};
    int lift{-1};
    int value1{-1};
    int value2{-1};
    int value3{-1};
};

HkPayloadView parsePayload(const QByteArray& payload)
{
    HkPayloadView view;
    if (payload.size() > 0) {
        view.agv = static_cast<uint8_t>(payload.at(0));
    }
    if (payload.size() > 1) {
        view.lift = static_cast<uint8_t>(payload.at(1));
    }
    if (payload.size() > 2) {
        view.value1 = static_cast<uint8_t>(payload.at(2));
    }
    if (payload.size() > 3) {
        view.value2 = static_cast<uint8_t>(payload.at(3));
    }
    if (payload.size() > 4) {
        view.value3 = static_cast<uint8_t>(payload.at(4));
    }
    return view;
}

QString payloadHex(const QByteArray& payload)
{
    return QString::fromUtf8(payload.toHex(' '));
}
} // namespace

// ==================== TCP协议类实现 ====================

namespace hk {

class Protocol::TcpConnection : public QObject {
    Q_OBJECT
public:
    TcpConnection(QObject* parent = nullptr) : QObject(parent) {
        m_socket = new QTcpSocket(this);
        connect(m_socket, &QTcpSocket::readyRead, this, &TcpConnection::onReadyRead);
        connect(m_socket, &QTcpSocket::stateChanged, this, &TcpConnection::onStateChanged);
    }

    ~TcpConnection() {
        if (m_socket->isOpen()) {
            m_socket->close();
        }
    }

    bool connectToHost(const QHostAddress& address, int port) {
        m_socket->connectToHost(address, port);
        return m_socket->waitForConnected(3000);  // 3秒超时
    }

    bool isOpen() const {
        return m_socket->state() == QAbstractSocket::ConnectedState;
    }

    bool isReadable() const {
        return m_socket->isReadable();
    }

    qint64 write(const QByteArray& data) {
        return m_socket->write(data);
    }

    bool waitForBytesWritten(int msecs) {
        return m_socket->waitForBytesWritten(msecs);
    }

    QByteArray read(qint64 maxSize) {
        return m_socket->read(maxSize);
    }

signals:
    void readyRead();
    void stateChanged(QAbstractSocket::SocketState state);

private slots:
    void onReadyRead() {
        emit readyRead();
    }

    void onStateChanged(QAbstractSocket::SocketState state) {
        emit stateChanged(state);
    }

private:
    QTcpSocket* m_socket;
};

Protocol::Protocol() = default;
Protocol::~Protocol() {
    if (m_connection) {
        delete m_connection;
        m_connection = nullptr;
    }
}

void Protocol::init(const QHostAddress& liftIp, int liftPort, ProtocolCallback frameParse)
{
    m_frameParse = frameParse;

    // 创建TCP连接
    m_connection = new TcpConnection();

    if (!m_connection->connectToHost(liftIp, liftPort)) {
        qDebug() << "HKLift connect failed";
        return;
    }

    if (!m_connection->isOpen()) {
        qDebug() << "HKLift connection not open";
        return;
    }

    qDebug() << "HKLift connected successfully to" << liftIp.toString() << ":" << liftPort;

    // 连接信号
    connect(m_connection, &TcpConnection::readyRead, this, &Protocol::receiveReadyRead);
    connect(m_connection, &TcpConnection::stateChanged, this, &Protocol::stateChanged);
}

void Protocol::write(const QByteArray& sendData)
{
    // 参考 lift.cpp:280-322
    if (!m_connection || !m_connection->isOpen() || sendData.isEmpty()) {
        return;
    }

    const quint8 payloadLen = static_cast<quint8>(sendData.size() - 1); // 不包含命令字节

    // 报文格式：0xAB 0x66 0x00 0x00 [长度1字节] [命令+数据] 0x03
    QByteArray packet;
    packet.reserve(sendData.size() + 6);
    packet.append(char(0xAB));
    packet.append(char(0x66));
    packet.append(char(0x00));
    packet.append(char(0x00));
    packet.append(char(payloadLen));
    packet.append(sendData);
    packet.append(char(0x03));

    // 发送数据
    m_connection->write(packet);
    // qDebug() << "HKLift Send:" << packet.toHex(' ');

    // 等待写入完成
    m_connection->waitForBytesWritten(1000);
}

void Protocol::receiveReadyRead()
{
    // 参考 lift.cpp:324-380
    if (!m_connection || !m_connection->isOpen() || !m_connection->isReadable()) {
        return;
    }

    // 读取数据
    QByteArray message = m_connection->read(INT16_MAX);
    message = m_lastMessage + message;
    m_lastMessage.clear();

    // qDebug() << "HKLift Receive:" << message.toHex(' ');

    while (message.size() >= 7) {
        if (static_cast<uint8_t>(message.at(0)) != 0xAB ||
            static_cast<uint8_t>(message.at(1)) != 0x66) {
            // 报头不对，丢弃首字节后继续
            message.remove(0, 1);
            continue;
        }

        if (message.size() < 6) {
            break;
        }

        const int payloadLen = static_cast<uint8_t>(message.at(4));
        const int totalLen = 4 + 1 + 1 + payloadLen + 1; // header + len + (cmd+payload) + tail

        if (message.size() < totalLen) {
            // 数据未接收完整，缓存等待下一次
            break;
        }

        if (static_cast<uint8_t>(message.at(totalLen - 1)) != 0x03) {
            // 结束符不匹配，丢弃报头继续尝试
            message.remove(0, 1);
            continue;
        }

        QByteArray data = message.mid(5, 1 + payloadLen);
        if (m_frameParse) {
            m_frameParse(data);
        }

        message.remove(0, totalLen);
    }

    if (!message.isEmpty()) {
        m_lastMessage = message;
    }
}

} // namespace hk

// ==================== HKLift实现 ====================

HKLift::HKLift(int liftNum,
               const QString& liftIp,
               int liftPort,
               std::shared_ptr<kernel::ILogger> logger,
               QObject* parent)
    : BaseLift(liftNum, LiftType::HK, logger, parent)
    , m_liftIp(liftIp)
    , m_liftPort(liftPort)
{
}

bool HKLift::initialize()
{
    // 参考 lift.cpp:18-24
    m_protocol.init(
        QHostAddress(m_liftIp),
        m_liftPort,
        std::bind(&HKLift::frameParse, this, std::placeholders::_1)
    );

    if (m_logger) {
        m_logger->info(QString("HKLift %1 initialized: %2:%3")
            .arg(m_liftNum)
            .arg(m_liftIp)
            .arg(m_liftPort));
    }

    return true;
}

bool HKLift::request(const LiftRequestInfo& requestInfo)
{
    // 设置电梯信息并开始请求流程
    m_aimFloor = requestInfo.targetFloor.floor;
    m_callFloor = requestInfo.startFloor.floor;
    setCurrentRequest(requestInfo);

    // 开始状态查询
    setStage(LiftStage::QueryStatus);
    setStatus(LiftStatus::Idle);

    if (m_logger) {
        m_logger->info(QString("HKLift %1 request: floor %2 -> %3")
            .arg(m_liftNum)
            .arg(m_callFloor)
            .arg(m_aimFloor));
    }

    return true;
}

bool HKLift::release()
{
    clearPendingCallback();
    taskOver();
    unlock();
    setCurrentRequest(LiftRequestInfo{});

    if (m_logger) {
        m_logger->info(QString("HKLift %1 released").arg(m_liftNum));
    }

    return true;
}

// ==================== 海康电梯API ====================

void HKLift::requestLiftStatus(const QString& uuid, LiftResponseCallback callback)
{
    // 参考 lift.cpp:39-54
    QByteArray data;
    data.resize(4);
    data[0] = 0x01;  // 命令：查询状态
    data[1] = 0x00;  // 保留
    data[2] = 0xFF;  // 全部电梯
    data[3] = 0x00;

    m_protocol.write(data);
    m_callback = callback;
    m_dataId = uuid;
    m_curDataId = uuid;

    if (m_logger) {
        m_logger->debug(QString("HKLift %1: request_lift_status").arg(m_liftNum));
    }
}

void HKLift::requestLiftCall(int liftNum, int callFloor, int aimFloor, LiftResponseCallback callback)
{
    // 参考 lift.cpp:111-122
    QByteArray data;
    data.resize(5);
    data[0] = 0x02;      // 命令：呼叫电梯
    data[1] = 0x00;      // AGV编号（待配置）
    data[2] = 0x00;      // 预留/电梯编号
    data[3] = callFloor; // 呼叫楼层
    data[4] = 0x00;      // 预留

    m_protocol.write(data);
    m_callback = callback;

    if (m_logger) {
        m_logger->info(QString("HKLift %1: call from floor %2 to %3")
            .arg(liftNum)
            .arg(callFloor)
            .arg(aimFloor));
    }
}

void HKLift::requestLiftInLiftCloseDoor(int liftNum, LiftResponseCallback callback)
{
    Q_UNUSED(liftNum);
    const QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
    requestDoorClose(uuid, callback);

    if (m_logger) {
        m_logger->debug(QString("HKLift %1: in_lift_close_door (door close cmd)").arg(m_liftNum));
    }
}

void HKLift::requestLiftOutLiftCloseDoor(int liftNum, LiftResponseCallback callback)
{
    Q_UNUSED(liftNum);
    const QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
    requestDoorClose(uuid, callback);

    if (m_logger) {
        m_logger->debug(QString("HKLift %1: out_lift_close_door (door close cmd)").arg(m_liftNum));
    }
}

void HKLift::requestDoorOpen(const QString& uuid, LiftResponseCallback callback)
{
    // 参考 lift.cpp:78-90
    QByteArray data;
    data.resize(4);
    data[0] = 0x03;  // 命令：开门
    data[1] = 0x00;  // 保留
    data[2] = 0x10;  // 前门
    data[3] = 0x00;

    m_protocol.write(data);
    m_callback = callback;
    m_dataId = uuid;
    m_curDataId = uuid;
}

void HKLift::requestDoorClose(const QString& uuid, LiftResponseCallback callback)
{
    // 参考 lift.cpp:64-76
    QByteArray data;
    data.resize(4);
    data[0] = 0x08;  // 命令：关门
    data[1] = 0x00;  // AGV编号
    data[2] = 0x10;  // 前门
    data[3] = 0x00;

    m_protocol.write(data);
    m_callback = callback;
    m_dataId = uuid;
    m_curDataId = uuid;
}

void HKLift::openFrontDoor(const QString& uuid)
{
    requestDoorOpen(uuid, nullptr);
}

void HKLift::closeFrontDoor(const QString& uuid)
{
    requestDoorClose(uuid, nullptr);
}

void HKLift::sendCustomData(const QString& uuid, const QByteArray& data, ResponseCallback callback)
{
    m_protocol.write(data);
    m_callback = callback;
    m_dataId = uuid;
    m_curDataId = uuid;
}

void HKLift::clearPendingCallback()
{
    if (!m_callback && m_dataId.isEmpty() && m_curDataId.isEmpty()) {
        return;
    }

    m_callback = nullptr;
    m_dataId.clear();
    m_curDataId.clear();

    if (m_logger) {
        m_logger->debug(QString("HKLift %1: pending callbacks cleared").arg(m_liftNum));
    }
}

// ==================== 响应处理 ====================

void HKLift::responseLiftStatus(const QByteArray& payload)
{
    const int payloadLen = payload.size();
    const int floor = (payloadLen >= 2) ? static_cast<uint8_t>(payload.at(payloadLen - 3)) : -1;
    const int doorState = (payloadLen >= 1) ? static_cast<uint8_t>(payload.at(payloadLen - 2)) : -1;

    if (m_callback) {
        m_callback();
        m_callback = nullptr;
    }

    setStatus(LiftStatus::Idle);

    if (m_stage == LiftStage::QueryStatus) {
        setStage(LiftStage::QueryStatusResponse);
    }

    handleStatusTransition(floor, doorState);

    if (m_logger) {
        m_logger->debug(QString("HKLift %1: status ack floor=%2 state=0x%3 payload=%4")
                            .arg(m_liftNum)
                            .arg(floor)
                            .arg(doorState, 2, 16, QChar('0'))
                            .arg(payloadHex(payload)));
    }
}

void HKLift::responseLiftCall(const QByteArray& payload)
{
    const auto fields = parsePayload(payload);

    if (m_callback) {
        m_callback();
        m_callback = nullptr;
    }

    setStatus(LiftStatus::Idle);

    if (m_logger) {
        const int liftNum = (fields.lift >= 0) ? fields.lift : m_liftNum;
        const int targetFloor = (fields.value1 >= 0) ? fields.value1 : -1;
        const int callFloor = (fields.value2 >= 0) ? fields.value2 : -1;
        m_logger->info(QString("HKLift %1: call ack target=%2 call=%3 payload=%4")
                           .arg(liftNum)
                           .arg(targetFloor)
                           .arg(callFloor)
                           .arg(payloadHex(payload)));
    }
}

void HKLift::responseLiftInLiftCloseDoor(const QByteArray& payload)
{
    const auto fields = parsePayload(payload);

    if (m_callback) {
        m_callback();
        m_callback = nullptr;
    }

    setStatus(LiftStatus::Idle);

    if (m_logger) {
        const int liftNum = (fields.lift >= 0) ? fields.lift : m_liftNum;
        const int floor = (fields.value1 >= 0) ? fields.value1 : -1;
        m_logger->info(QString("HKLift %1: in-lift door close ack floor=%2 payload=%3")
                           .arg(liftNum)
                           .arg(floor)
                           .arg(payloadHex(payload)));
    }
}

void HKLift::responseLiftOutLiftCloseDoor(const QByteArray& payload)
{
    const auto fields = parsePayload(payload);

    if (m_callback) {
        m_callback();
        m_callback = nullptr;
    }

    setStatus(LiftStatus::Idle);

    if (m_logger) {
        const int liftNum = (fields.lift >= 0) ? fields.lift : m_liftNum;
        const int floor = (fields.value1 >= 0) ? fields.value1 : -1;
        m_logger->info(QString("HKLift %1: out-lift door close ack floor=%2 payload=%3")
                           .arg(liftNum)
                           .arg(floor)
                           .arg(payloadHex(payload)));
    }
}

void HKLift::beRequestedLiftOnCallLayer(const QByteArray& payload)
{
    const auto fields = parsePayload(payload);
    const int liftNum = (fields.lift >= 0) ? fields.lift : m_liftNum;
    const int floorNum = (fields.value1 >= 0) ? fields.value1 : -1;

    changeStage(LiftStage::ArriveCallFloor);
    setStatus(LiftStatus::Idle);
    responseLiftOnCallLayer(liftNum, 0);

    if (m_logger) {
        m_logger->info(QString("HKLift %1: arrived at call floor %2 payload=%3")
                           .arg(liftNum)
                           .arg(floorNum)
                           .arg(payloadHex(payload)));
    }
}

void HKLift::responseLiftOnCallLayer(int liftNum, int contentNum)
{
    // 参考 lift.cpp:152-161
    // AGV回复电梯：已收到到达呼叫楼层的通知
    QByteArray data;
    data.resize(4);
    data[0] = 0x14;  // 命令：回复到达呼叫楼层
    data[1] = 0x00;  // AGV编号
    data[2] = liftNum;
    data[3] = contentNum;

    m_protocol.write(data);

    if (m_logger) {
        m_logger->debug(QString("HKLift %1: response_lift_on_call_layer").arg(liftNum));
    }
}

void HKLift::beRequestedLiftOnAimLayer(const QByteArray& payload)
{
    const auto fields = parsePayload(payload);
    const int liftNum = (fields.lift >= 0) ? fields.lift : m_liftNum;
    const int floorNum = (fields.value1 >= 0) ? fields.value1 : -1;

    changeStage(LiftStage::ArriveAimFloor);
    setStatus(LiftStatus::Idle);
    responseLiftOnAimLayer(liftNum, 0);

    if (m_logger) {
        m_logger->info(QString("HKLift %1: arrived at target floor %2 payload=%3")
                           .arg(liftNum)
                           .arg(floorNum)
                           .arg(payloadHex(payload)));
    }
}

void HKLift::responseLiftOnAimLayer(int liftNum, int contentNum)
{
    // 参考 lift.cpp:175-184
    // AGV回复电梯：已收到到达目标楼层的通知
    QByteArray data;
    data.resize(4);
    data[0] = 0x16;  // 命令：回复到达目标楼层
    data[1] = 0x00;  // AGV编号
    data[2] = liftNum;
    data[3] = contentNum;

    m_protocol.write(data);

    if (m_logger) {
        m_logger->debug(QString("HKLift %1: response_lift_on_aim_layer").arg(liftNum));
    }
}

void HKLift::handleDoorCommandAck(uint8_t command, const QByteArray& payload)
{
    const auto fields = parsePayload(payload);

    if (m_callback) {
        m_callback();
        m_callback = nullptr;
    }

    setStatus(LiftStatus::Idle);

    if (m_logger) {
        const int liftNum = (fields.lift >= 0) ? fields.lift : m_liftNum;
        const int floor = (fields.value1 >= 0) ? fields.value1 : -1;
        const int doorCode = fields.value2;
        QString action = QStringLiteral("door command");
        if (doorCode == 0x03 || command == 0x03 || command == 0x83) {
            action = QStringLiteral("door open");
        } else if (doorCode == 0x08 || command == 0x08) {
            action = QStringLiteral("door close");
        }
        m_logger->info(QString("HKLift %1: %2 ack floor=%3 payload=%4")
                           .arg(liftNum)
                           .arg(action)
                           .arg(floor)
                           .arg(payloadHex(payload)));
    }
}

void HKLift::handleStatusTransition(int floor, int doorState)
{
    if (floor < 0 || doorState < 0) {
        return;
    }

    const bool doorOpen = (doorState == 0x08);

    if ((m_stage == LiftStage::Call || m_stage == LiftStage::CallResponse) &&
        floor == m_callFloor && doorOpen) {
        setStage(LiftStage::ArriveCallFloor);
        setStatus(LiftStatus::Idle);
        return;
    }

    if ((m_stage == LiftStage::ArriveAimFloorResponse ||
         m_stage == LiftStage::InCloseDoorResponse) &&
        floor == m_aimFloor && doorOpen) {
        setStage(LiftStage::ArriveAimFloor);
        setStatus(LiftStatus::Idle);
    }
}


// ==================== 状态控制 ====================

void HKLift::changeStage(LiftStage stage)
{
    setStage(stage);

    if (m_logger) {
        m_logger->debug(QString("HKLift %1: stage changed to %2")
            .arg(m_liftNum)
            .arg(static_cast<int>(stage)));
    }
}

void HKLift::taskOver()
{
    setStatus(LiftStatus::Idle);
    setStage(LiftStage::Done);

    if (m_logger) {
        m_logger->info(QString("HKLift %1: task over").arg(m_liftNum));
    }
}

void HKLift::frameParse(QByteArray& data)
{
    if (data.isEmpty()) {
        return;
    }

    const uint8_t command = static_cast<uint8_t>(data.at(0));
    const QByteArray payload = data.mid(1);

    auto warnUnknown = [&](const QString& message) {
        if (!m_logger) {
            return;
        }
        m_logger->warning(QString("HKLift %1: %2 cmd=0x%3 payload=%4")
                              .arg(m_liftNum)
                              .arg(message)
                              .arg(command, 2, 16, QChar('0'))
                              .arg(payloadHex(payload)));
    };

    const uint8_t normalized = static_cast<uint8_t>((command >= 0x80) ? (command & 0x7F) : command);

    switch (normalized) {
        case 0x01:
            responseLiftStatus(payload);
            break;

        case 0x02:
            responseLiftCall(payload);
            break;

        case 0x03:
        case 0x08:
            handleDoorCommandAck(command, payload);
            break;

        default:
            warnUnknown(QStringLiteral("unknown command"));
            break;
    }
}

} // namespace lift
} // namespace application

 #include "hk_lift.moc"
